﻿namespace NTLib.Pipe.Network.UTest.Provider
{
    using Descriptors;
    using Formats;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Network.Connectors;
    using Providers;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using Test.Resources;
    using NTLib.Core.Win.Net;
    using NTLib.Core.Tasks;
    using Pipe.Containers;
    using Exceptions;
    using Streaming.Formats;

    [TestClass]
    public class NetworkPipeProviderUTest : BaseTestClass
    {
        #region Methods

        #region Method

        [TestCategory("Pipe.Memory.Provider")]
        [TestMethod]
        public void NetworkPipeProvider_CreateAndGetSimple()
        {
            var prov = new NetworkPipeProvider();
            var prov2 = new NetworkPipeProvider();
            var guid = Guid.NewGuid();
            DataStruct data = new DataStruct();
            data.Msg = guid.ToString();

            CancellationTokenSource timeout = CreateTimeout(15);

            var ipaddr = IPAddress.Loopback;
            var port = ipaddr.GetFreePort();
            Uri addr = new Uri("Tcp://" + ipaddr.ToString() + ":" + port, UriKind.RelativeOrAbsolute);

            NetworkTargetDescription targetH = NetworkTargetDescription.Create<TcpConnector, SimpleJsonPackageFormater>(addr, true, Guid.NewGuid());
            NetworkTargetDescription target = NetworkTargetDescription.Create<TcpConnector, SimpleJsonPackageFormater>(addr, false, Guid.NewGuid());

            using (var pipe = prov.CreateAsync<DataStruct>(PipeType.TwoWay, targetH).WaitResult())
            {
                Assert.IsInstanceOfType(pipe, typeof(IPipeManipulatorOwner<DataStruct>));

                pipe.SendAsync(data).Wait(timeout.Token);

                prov2.RegisterOutLessPipeAsync(pipe.Id, target, PipeType.TwoWay).Wait(timeout.Token);

                try
                {
                    prov.GetPipeAsync<DataStruct>(pipe.Id).Wait(timeout.Token);
                }
                catch (Exception ex)
                {
                    Assert.IsTrue(ExceptionTest<PipeSourceAlreadyPresentInThisProviderException>(ex));
                }

                using (var twowaypipe = prov2.GetPipeAsync<DataStruct>(pipe.Id).WaitResult())
                {

                    Assert.IsInstanceOfType(twowaypipe, typeof(IPipeManipulator<DataStruct>));
                    Assert.IsInstanceOfType(twowaypipe, typeof(TwoWayPipe<DataStruct>));


                    var dataRead = twowaypipe.PopAsync().WaitResult(timeout.Token);

                    Assert.AreNotEqual(dataRead, null);
                    Assert.AreEqual(data.Msg, dataRead.Msg);

                    data = new DataStruct();
                    data.Msg = Guid.NewGuid().ToString();
                    twowaypipe.SendAsync(data).Wait(timeout.Token);

                    dataRead = pipe.PopAsync().WaitResult(timeout.Token);

                    Assert.AreNotEqual(dataRead, null);
                    Assert.AreEqual(data.Msg, dataRead.Msg);
                }
            }
        }

        //[TestCategory("Pipe.Memory.Provider")]
        //[TestMethod]
        //public void MemoryPipeProvider_CreateAndGetSimpleOneWay()
        //{
        //    var prov = new MemoryProvider();
        //    var guid = Guid.NewGuid();
        //    DataStruct data = new DataStruct();
        //    data.Data = guid.ToString();
        //    using (var pipe = prov.CreateAsync<DataStruct>(PipeType.OneWay, LocalTargetDescription.Instance).WaitResult())
        //    {
        //        Assert.IsInstanceOfType(pipe, typeof(IPipeManipulatorOwner<DataStruct>));
        //        Assert.IsInstanceOfType(pipe, typeof(PushOnlyPipeOwner<DataStruct>));

        //        pipe.SendAsync(data).Wait();

        //        using (var readPipe = prov.GetPipeAsync<DataStruct>(pipe.Id).WaitResult())
        //        {
        //            Assert.AreNotEqual(readPipe, null);
        //            Assert.IsInstanceOfType(readPipe, typeof(IPipeManipulator<DataStruct>));
        //            Assert.IsInstanceOfType(readPipe, typeof(ReadOnlyPipe<DataStruct>));

        //            var dataRead = readPipe.PopAsync().WaitResult();

        //            Assert.AreNotEqual(dataRead, null);
        //            Assert.AreEqual(data.Data, dataRead.Data);
        //        }
        //    }
        //}

        //[TestCategory("Pipe.Memory.Provider")]
        //[TestMethod]
        //public void MemoryPipeProvider_CreateAndGetSimpleFromTarget()
        //{
        //    var prov = new MemoryProvider();
        //    var guid = Guid.NewGuid();
        //    DataStruct data = new DataStruct();
        //    data.Data = guid.ToString();
        //    using (var pipe = prov.CreateAsync<DataStruct>(PipeType.FromTarget, LocalTargetDescription.Instance).WaitResult())
        //    {
        //        Assert.IsInstanceOfType(pipe, typeof(IPipeManipulatorOwner<DataStruct>));
        //        Assert.IsInstanceOfType(pipe, typeof(ReadOnlyPipeOwner<DataStruct>));

        //        using (var sendPipe = prov.GetPipeAsync<DataStruct>(pipe.Id).WaitResult())
        //        {

        //            Assert.IsInstanceOfType(sendPipe, typeof(IPipeManipulator<DataStruct>));
        //            Assert.IsInstanceOfType(sendPipe, typeof(PushOnlyPipe<DataStruct>));

        //            sendPipe.SendAsync(data).Wait();

        //            var dataRead = pipe.PopAsync().WaitResult();

        //            Assert.AreNotEqual(dataRead, null);
        //            Assert.AreEqual(data.Data, dataRead.Data);
        //        }
        //    }
        //}

        //[TestCategory("Pipe.Memory.Provider")]
        //[TestMethod]
        //public void MemoryPipeProvider_CanGet()
        //{
        //    var prov = new MemoryProvider();

        //    using (var pipe = prov.CreateAsync<DataStruct>(PipeType.TwoWay, LocalTargetDescription.Instance).WaitResult())
        //    {
        //        Assert.IsTrue(prov.CanGetPipeAsync(pipe.Id).WaitResult());
        //    }

        //    using (var pipe = prov.CreateAsync<DataStruct>(PipeType.FromTarget, LocalTargetDescription.Instance).WaitResult())
        //    {
        //        Assert.IsTrue(prov.CanGetPipeAsync(pipe.Id).WaitResult());
        //    }

        //    using (var pipe = prov.CreateAsync<DataStruct>(PipeType.OneWay, LocalTargetDescription.Instance).WaitResult())
        //    {
        //        Assert.IsTrue(prov.CanGetPipeAsync(pipe.Id).WaitResult());
        //    }
        //}

        #endregion endregion

        #endregion
    }
}
